package cn.softgame.jserver.connector.tcp;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

import cn.softgame.jserver.connector.SocketDataHandler;
import cn.softgame.jserver.queue.QueueFactory;

/**
 * TCP客户端程序
 * 向服务器端发送TCP数据包，接受服务器端响应的TCP数据包
 * @author xuquan
 * 日期:2013-5-28
 */
public class TCPClient implements Runnable{
	private SocketDataHandler socketDataHandler;
	private Selector selector;
	private volatile SocketChannel sc;
	private volatile boolean longConnection;
	
	public TCPClient(boolean longConnection){
		try {
			socketDataHandler=new SocketDataHandler(QueueFactory.TCP_QUEUE);
			selector = Selector.open();
			this.longConnection=longConnection;
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void openSocketChannel(String url,int port) {
		try {
			sc = SocketChannel.open();
			sc.configureBlocking(false);
			
			InetSocketAddress socketAddress=new InetSocketAddress(url, port);
			sc.connect(socketAddress);
			sc.register(selector, SelectionKey.OP_CONNECT);
		} catch (ClosedChannelException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void run(){
		try {
			while(!Thread.interrupted()){
				if(selector.select(30)>0){
					doSelector(selector);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void doSelector(Selector selector) {
		Set<SelectionKey> readyKeys = selector.selectedKeys();
		Iterator<SelectionKey> iter=readyKeys.iterator();
		while(iter.hasNext()){
			SelectionKey key = iter.next();
			iter.remove();
			doKey(key);
			readyKeys.clear();
		}
	}

	private void doKey(SelectionKey key) {
		try {
			if(key.isConnectable()){ //连接成功
				SocketChannel keyChannel = (SocketChannel) key.channel();
				if(keyChannel.isConnectionPending()){
					keyChannel.finishConnect();
				}
				sendRequest(key);
			}else if(key.isReadable()){ //如果可以从服务器读取response数据
				receiveResponse(key);
				if(!longConnection)
					close();
			}else if(key.isWritable()){ //如果可以向服务器发送request数据
				sendRequest(key);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void receiveResponse(SelectionKey key) throws IOException {
		try{
			byte[] array = socketDataHandler.getByte();
			ByteBuffer buffer = ByteBuffer.wrap(array);
			SocketChannel keyChannel = (SocketChannel) key.channel();
			keyChannel.read(buffer);
			socketDataHandler.receiveResponse(array);
			key.interestOps(SelectionKey.OP_WRITE);
			selector.wakeup();
		}catch(Exception e){
			e.printStackTrace();
		}
	}

	private void sendRequest(SelectionKey key) {
		try {
			byte[] request = socketDataHandler.sendRequest();
			ByteBuffer buffer = ByteBuffer.wrap(request);
			SocketChannel keyChannel = (SocketChannel) key.channel();
			keyChannel.write(buffer);
			key.interestOps(SelectionKey.OP_READ);
			selector.wakeup();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void close(){
		if(sc!=null){
			try {
				SelectionKey key = sc.keyFor(selector);
				key.cancel();
				sc.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
}
